using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace InventorySystem
{
    public class Inventory : MonoBehaviour
    {
        [SerializeField]
        private int _size = 6; // 背包大小
        [SerializeField]
        private List<InventorySlot> _slots; // 物品槽列表

        public int Size => _size;

        public List<InventorySlot> Slots => _slots;

        private int _activeSlotIndex;

        public int ActiveSlotIndex
        {
            get => _activeSlotIndex;
            private set
            {
                _slots[_activeSlotIndex].Active = false;
                _activeSlotIndex = value < 0 ? _size - 1 : value % Size;// 如果索引小于0，循环到最后一个物品槽；否则取模获取合法索引
                _slots[_activeSlotIndex].Active = true;
            }
        }

        public void ActivateSlot(int atIndex)
        {
            ActiveSlotIndex = atIndex;
        }

        public bool HasItem(ItemStack itemStack, bool checkNumberOfItems = false)
        {
            var itemSlot = FindSlot(itemStack.Item);
            if (itemSlot == null) return false;
            if (!checkNumberOfItems) return true;
            if (itemStack.Item.IsStackable)
            {
                return itemSlot.NumberOfItems >= itemStack.NumberOfItems; // 检查物品数量是否足够
            }
            return _slots.Count(slot => slot.Item == itemStack.Item) >= itemStack.NumberOfItems;// 检查物品槽数量是否足够
        }

        public void ClearSlot(int atIndex)
        {
            _slots[atIndex].Clear();
        }

        // public ItemStack RemoveItem(ItemStack itemStack)
        // {
        //     var itemSlot = FindSlot(itemStack.Item);
        //     if (itemSlot == null)
        //         throw new InventoryException(InventoryOperation.Remove, "库存中没有物品");
        //     if (itemSlot.Item.IsStackable && itemSlot.NumberOfItems < itemStack.NumberOfItems)
        //         throw new InventoryException(InventoryOperation.Remove, "物品不足");
        //     itemSlot.NumberOfItems -= itemStack.NumberOfItems;// 移除指定数量的物品
        //     if (itemSlot.Item.IsStackable && itemSlot.NumberOfItems > 0)
        //     {
        //         return itemSlot.State;
        //     }
        //     itemSlot.Clear();
        //     return new ItemStack(null, 0);
        // }

        public ItemStack RemoveItem(int atIndex, bool spawn = false)
        {
            if (!_slots[atIndex].HasItem)
                throw new InventoryException(InventoryOperation.Remove, "槽位为空");
            // if (spawn)
            // {
            //     // 添加生成物品的逻辑
            // }
            if (spawn && TryGetComponent<GameItemSpawner>(out var itemSpawner))
            {
                // 添加生成物品的逻辑
                itemSpawner.SpawnItem(_slots[atIndex].State);
            }
            ClearSlot(atIndex);
            return new ItemStack(null, 0);
            
        }

        private void Awake()
        {
            if (_size > 0)
            {
                _slots[0].Active = true;// 激活第一个物品槽
            }
        }

        public void Activateslot(int atIndex)
        {
            ActiveSlotIndex = atIndex;
        }
        // public InventorySlot GetActiveslot()
        // {
        //     return _slots[ActiveSlotIndex];
        // }

        private void OnValidate()
        {
            AdjustSize(); // 检查并调整背包大小
        }

        /// <summary>
        /// 检查并调整背包大小
        /// </summary>
        private void AdjustSize()
        {
            _slots ??= new List<InventorySlot>(); // 如果物品槽列表为空，则初始化为一个空的列表
            if (_slots.Count > _size) // 如果物品槽数量大于背包大小
                _slots.RemoveRange(_size, _slots.Count - _size); // 移除多余的物品槽
            if (_slots.Count < _size) // 如果物品槽数量小于背包大小
                _slots.AddRange(new InventorySlot[_size - _slots.Count]); // 添加空的物品槽，直到数量达到背包大小
        }

        /// <summary>
        /// 判断背包是否已满
        /// </summary>
        public bool IsFull()
        {
            return _slots.Count(slot => slot.HasItem) >= _size; // 如果已占用的物品槽数量大于等于背包大小，则背包已满
        }

        /// <summary>
        /// 判断是否可以接收物品堆叠
        /// </summary>
        /// <param name="itemStack">物品堆叠</param>
        /// <returns>如果可以接收，则返回true；否则返回false</returns>
        public bool CanAcceptItem(ItemStack itemStack)
        {
            var slotWithStackableItem = FindSlot(itemStack.Item, onlyStackable: true); // 查找可以堆叠的物品槽
            return !IsFull() || slotWithStackableItem != null; // 如果背包未满或找到了一个可以堆叠的物品槽，就可以接收该物品
        }

        /// <summary>
        /// 查找具有指定物品的物品槽
        /// </summary>
        /// <param name="item">物品定义</param>
        /// <param name="onlyStackable">是否只查找可堆叠的物品槽</param>
        /// <returns>如果找到，返回具有指定物品的物品槽；否则返回null</returns>
        private InventorySlot FindSlot(ItemDefinition item, bool onlyStackable = false)
        {
            // 遍历物品槽列表，找到第一个物品槽的Item属性等于指定物品的Item属性，并且该物品符合是否只查找可堆叠的物品槽的要求
            return _slots.FirstOrDefault(slot => slot.Item == item && (item.IsStackable || !onlyStackable));
        }

        /// <summary>
        /// 向背包中添加物品堆叠
        /// </summary>
        /// <param name="itemStack">物品堆叠</param>
        /// <returns>实际添加到背包中的物品堆叠</returns>
        public ItemStack AddItem(ItemStack itemStack)
        {
            var relevantSlot = FindSlot(itemStack.Item, true); // 查找具有相同物品的物品槽
            if (IsFull() && relevantSlot == null) // 如果背包已满并且无法找到可以堆叠的物品槽，就抛出异常
            {
                throw new InventoryException(InventoryOperation.Add, "Inventory is full");
            }
            if (relevantSlot != null) // 如果找到了可以堆叠的物品槽
            {
                relevantSlot.NumberOfItems += itemStack.NumberOfItems; // 合并物品堆叠数量
            }
            else // 如果没有找到可以堆叠的物品槽
            {
                relevantSlot = _slots.First(slot => !slot.HasItem); // 找到第一个空的物品槽
                relevantSlot.State = itemStack; // 设置该物品槽的物品堆叠为指定的物品堆叠
            }
            return relevantSlot.State; // 返回实际添加到背包中的物品堆叠
        }
    }
}
